package com.yugao.fintech.antelope.mps.core.parser;

import com.yugao.fintech.antelope.mps.api.constatnts.ChannelTypeEnum;
import com.yugao.fintech.antelope.mps.api.model.content.template.TemplateVarData;
import com.yugao.fintech.antelope.mps.model.entity.MsgTemplate;
import com.yugao.fintech.antelope.mps.utils.VelocityUtil;
import com.yugao.fintech.framework.assistant.utils.StringUtils;
import com.yugao.fintech.framework.assistant.utils.exception.BizException;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.VelocityContext;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;

import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 模板基础层
 */
@Slf4j
public abstract class AbstractTemplateParser {
    private static final Map<ChannelTypeEnum, AbstractTemplateParser> subClassMap = new HashMap<>();

    /**
     * key: 是调用方传递的模板数据的key
     * value.key: 是映射的模板key
     */
    @Getter
    @Setter
    protected Map<String, TemplateVarData> varData = new HashMap<>();

    /**
     * 模板内容
     */
    @Getter
    @Setter
    protected String content;

    /**
     * 渲染结果
     */
    @Getter
    @Setter
    protected String renderContent;

    /**
     * 页面url
     */
    @Getter
    @Setter
    protected String pageUrl;

    public static void initTemplate() throws Exception {
        Reflections reflection = new Reflections(new ConfigurationBuilder()
                .setScanners(Scanners.SubTypes)
                .setUrls(ClasspathHelper.forPackage(AbstractTemplateParser.class.getPackage().getName()))
                .filterInputsBy(new FilterBuilder()));
        Set<Class<? extends AbstractTemplateParser>> subTypesOf = reflection.getSubTypesOf(AbstractTemplateParser.class);
        for (Class<? extends AbstractTemplateParser> subClass : subTypesOf) {
            try {
                boolean isAbstract = Modifier.isAbstract(subClass.getModifiers());
                if (isAbstract) {
                    continue;
                }

                AbstractTemplateParser obj = subClass.getDeclaredConstructor().newInstance();
                subClassMap.put(obj.channelType(), obj);
            } catch (Exception e) {
                log.info("inti class {} fail", subClass.getName());
                throw e;
            }
        }
    }

    public abstract ChannelTypeEnum channelType();

    /**
     * 将字符串转成当前对象
     *
     * @param jsonStr json字符串
     * @return 子类对象
     */
    protected abstract AbstractTemplateParser jsonToObj(String jsonStr);

    /**
     * 将模板内容渲染成目标内容, 比如将邮件模板渲染
     */
    public String evaluate() {
        if (StringUtils.isEmpty(content)) {
            return "";
        }
        List<TemplateVarData> tplDataList = new ArrayList<>(varData.values());
        VelocityContext velocityContext = new VelocityContext();
        tplDataList.forEach(e -> velocityContext.put(e.getKey(), e.getValue()));
        this.renderContent = VelocityUtil.generate(velocityContext, content);
        return this.renderContent;
    }

    /**
     * 通过模板变量渲染, 并返回渲染结果
     *
     * @param templateVars 模板变量
     * @return 结果
     */
    public String evaluate(List<TemplateVarData> templateVars) {
        if (StringUtils.isEmpty(content)) {
            return "";
        }
        VelocityContext velocityContext = new VelocityContext();
        templateVars.forEach(e -> velocityContext.put(e.getKey(), e.getValue()));
        this.renderContent = VelocityUtil.generate(velocityContext, content);
        return this.renderContent;
    }


    public static AbstractTemplateParser jsonToObj(ChannelTypeEnum channelType, String tplConfigJson) {
        AbstractTemplateParser value = subClassMap.get(channelType);
        if (Objects.isNull(value)) {
            throw new BizException("未找到 channelType 为 {} 的 {} 子类 ", channelType, AbstractTemplateParser.class.getName());
        }
        return value.jsonToObj(tplConfigJson);
    }

    /**
     * 完成字段映射与解析, 比如如果在页面上配置了映射 username(使用方使用的字段) => userName(消息模板中使用的字段)
     *
     * @param originalVarData 表示调用方传过来的模板数据
     */
    public static AbstractTemplateParser jsonToObj(List<TemplateVarData> originalVarData, MsgTemplate template, ChannelTypeEnum channelType) {
        String templateConfigStr = template.getTemplateConfig();
        AbstractTemplateParser value = subClassMap.get(channelType);
        if (Objects.isNull(value)) {
            throw new BizException("未找到 channelType 为 {} 的 {} 子类 ", channelType, AbstractTemplateParser.class.getName());
        }
        AbstractTemplateParser templateConfig = value.jsonToObj(templateConfigStr);

        // 开始映射字段
        Map<String, TemplateVarData> originalVarMap = originalVarData.stream()
                .collect(Collectors.toMap(TemplateVarData::getKey, Function.identity()));
        Map<String, TemplateVarData> varData = templateConfig.getVarData();
        varData.forEach((k, v) -> {
            TemplateVarData originalTplVarData = Optional.ofNullable(originalVarMap.get(k)).orElse(new TemplateVarData());
            // 优先采用页面上指定的值, 否则采用使用方传递的值
            if (Objects.isNull(v.getValue()) || StringUtils.isEmpty(v.getValue().toString())) {
                v.setValue(originalTplVarData.getValue());
            }
            v.setColor(originalTplVarData.getColor());
        });
        return templateConfig;
    }
}
